package com.shiguiwu.springmybatis.javabase.encrypt;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import cn.hutool.core.codec.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: stone
 * @date: Created by 2022/9/17 23:44
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.encrypt
 */
@Slf4j
public class RSAUtil {

    public static final String PUBLIC_KEY = "publicKey";

    public static final String PRIVATE_KEY = "privateKey";


    public static final String ALGORITHM_RSA = "RSA";

    public static Map<String, String> generateRASKey() {
        Map<String, String> rs = new HashMap<>();
        KeyPairGenerator keyPairGenerator = null;
        try {
            // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
            keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_RSA);
            //初始化
            keyPairGenerator.initialize(1024, new SecureRandom());

            //生成密钥对，保持在keyPari
            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            //得到私钥和公钥
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

            String publicKeyStr = Base64.encode(publicKey.getEncoded());
            rs.put(PUBLIC_KEY, publicKeyStr);
            String privateKeyStr = Base64.encode(privateKey.getEncoded());
            rs.put(PRIVATE_KEY, privateKeyStr);

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            log.error("加密失败 ====> {}", e.getMessage());
            throw new RuntimeException(e);
        }


        return rs;
    }


    public static void main(String[] args) {

        Map<String, String> map = generateRASKey();

        log.error("公钥 ===> {}", map.get(PUBLIC_KEY));
        log.warn("私钥 ===> {}", map.get(PRIVATE_KEY));

        JSONObject jsonObject = new JSONObject();
        jsonObject.set("username", "shiguiwu");
        jsonObject.set("password", "123456");

        String targetStr = JSONUtil.toJsonStr(jsonObject);

        String encryptPublicKey = encryptPublicKey(targetStr, map.get(PUBLIC_KEY));

        log.info("加密信息 ===> {}", encryptPublicKey);

        String decryptPrivateKey = decryptPrivateKey(encryptPublicKey, map.get(PRIVATE_KEY));

        log.info("解密信息 ===> {}", decryptPrivateKey);
    }


    /**
     * 公钥加密
     * @param source 明文信息
     * @param publicKey 公钥
     * @return 返回字符串
     *
     */
    public static String encryptPublicKey(String source, String publicKey)  {

        //base64编码的公钥
        byte[] decode = Base64.decode(publicKey);

        try {
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(ALGORITHM_RSA).generatePublic(new X509EncodedKeySpec(decode));

            //加密
            Cipher instance = Cipher.getInstance(ALGORITHM_RSA);
            instance.init(Cipher.ENCRYPT_MODE, pubKey);

            return Base64.encode(instance.doFinal(source.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {

            e.printStackTrace();
            log.error("加密失败 ====> {}", e.getMessage());
            throw new RuntimeException(e);
        }

    }




    /**
     * 私钥解密
     * @param source 加密信息
     * @param privateKey 私钥
     * @return 解密字符串
     */
    public static String decryptPrivateKey(String source, String privateKey) {
        //base64加密的后的字符串
        byte[] inputDecode =Base64.decode(source.getBytes(StandardCharsets.UTF_8));
        //base64的私钥
        byte[] decode =Base64.decode(privateKey);

        try {
            RSAPrivateKey generatePrivate = (RSAPrivateKey) KeyFactory.getInstance(ALGORITHM_RSA).generatePrivate(new PKCS8EncodedKeySpec(decode));

            //rsa解密
            Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
            //初始化
            cipher.init(Cipher.DECRYPT_MODE, generatePrivate);

            return new String(cipher.doFinal(inputDecode));

        } catch (Exception e) {
            e.printStackTrace();
            log.info("加密失败 ====> {}", e.getMessage());
            throw new RuntimeException(e);
        }

    }
}
